package com.cotte.flow.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.cotte.flow.hbase.dao.BrushCardDaoImpl;
import com.cotte.flow.hbase.dao.StepEmpDaoImpl;
import com.cotte.flow.hbase.dao.TransitDaoImpl;
import com.cotte.flow.hbase.record.BrushCardRecord;
import com.cotte.flow.hbase.record.StepEmpRecord;
import com.cotte.flow.hbase.record.TransitRecord;
import com.cotte.flow.model.DgraphRelations;
import com.cotte.flow.model.DgraphSteps;
import com.cotte.flow.model.Relation;
import com.cotte.flow.util.Client;
import com.cotte.flow.util.Transform;
import com.google.gson.Gson;
import com.google.protobuf.ByteString;

import io.dgraph.DgraphClient;
import io.dgraph.DgraphProto.Mutation;
import io.dgraph.DgraphProto.Response;
import io.dgraph.Transaction;

/**
 * 保存mes刷卡数据，计算占压工时和在途时间
* <p>Title: BrushCardService</p>  
* <p>Description: </p>  
* @author YGJ  
* @date 2018年12月4日
 */
@Service
public class BrushCardService {
	
	private static DgraphClient dgraphClient = Client.createDgraphClient(false);
	private static Gson gson = new Gson();
	private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
	@Autowired
	private BrushCardDaoImpl brushCardDao;
	
	@Autowired
	private StepEmpDaoImpl stepEmpDao;
	
	@Autowired
	private TransitDaoImpl transitDao;
	
	@Autowired
	private StepDgraphService stepDgraphService;
	
	@Value("${dgraph.steps.name.prefix}")
	private String STEP_NAME;
	@Value("${dgraph.relations.name.prefix}")
	private String RELATION_NAME;
	
	@Value("${dgraph.order.steps.name.prefix}")
	private String ORDER_STEP_NAME;
	
	@Value("${dgraph.order.relations.name.prefix}")
	private String ORDER_RELATION_NAME;
	
	/**
	 * 保存刷卡信息
	 * <p>Title: saveBrushCard</p>  
	 * <p>Description: </p>  
	 * @param map
	 */
	public void saveBrushCard(Map<String,String> map) {
		BrushCardRecord record = new BrushCardRecord();
		String odid_stepcode = map.get("odid") +"_"+map.get("stepCode");
		record.setOdid_stepcode(odid_stepcode);
		record.setStepcode(map.get("stepCode"));
		record.setSysCode(map.get("syscode"));
		record.setEmpcode(map.get("empCode"));
		record.setOrderCode(map.get("orderCode"));
		record.setLoadDate(map.get("loadDate"));
		brushCardDao.putRecord(record);
	}
	
	/**
	 * 更新占压
	 * <p>Title: updateOccupy</p>  
	 * <p>Description: </p>  
	 * @param syscode
	 * @param odid
	 */
	public Map<String,Object> updateOccupy(String version,String syscode,String odid,String stepcode) {
		Map<String,Object> map = new HashMap<>();
		/**
		 * 1.通过syscode 和 odid 查询订单工序图
		 * 2.根据当前查询订单的上道工序和下道工序
		 * 3.根据订单的parent 查询态势图
		 * 4.拿着上道工序下道工序和态势图名称查询占压
		 * 5.上道工序占压减1，下道工序占压加1，更新态势图的占压
		 */
		String orderStepName = ORDER_STEP_NAME+version+"_"+syscode+"_"+odid;
		DgraphSteps orderStep = stepDgraphService.getDgraphSteps(orderStepName);
		String parent = orderStep.getParentStep();
		String orderRelationName = ORDER_RELATION_NAME+version+"_"+syscode+"_"+odid;
		//根据当前工序查询上道工序和下道工序
		String pre_step = "{\r\n" + 
				"  pre_step(func:eq(D_relations_name, \"%s\")){\r\n" + 
				"    uid\r\n" + 
				"    relations @filter(eq(to,\"%s\")){\r\n" + 
				"      uid\n"+
				"      from\r\n" + 
				"      to\r\n" + 
				"    }\r\n" + 
				"  }\r\n" + 
				"}";
		String format_pre = String.format(pre_step, orderRelationName,stepcode);
		Response response_pre = dgraphClient.newReadOnlyTransaction().query(format_pre);
		String json_pre = Transform.jsonTransform(response_pre,"pre_step");
		DgraphRelations dgraphRelations_pre = gson.fromJson(json_pre, DgraphRelations.class);
		if(null != dgraphRelations_pre) {
			List<Relation> pre_relations = dgraphRelations_pre.getRelations();
			map.put("preRelation", pre_relations);
			map.put("root_uid", dgraphRelations_pre.getUid());
			for(Relation rel:pre_relations) {
				String from = rel.getFrom();
				String to = stepcode;
				//到态势图中查询占压,并减1
				String type = "reduce";
				upOccupy(parent,from,to,type);
			}
		}
		String next_step = "{\r\n" + 
				"  next_step(func:eq(D_relations_name, \"%s\")){\r\n" + 
				"    uid\r\n" + 
				"    relations @filter(eq(from,\"%s\")){\r\n" +
				"      from\r\n" + 
				"      to\r\n" + 
				"    }\r\n" + 
				"  }\r\n" + 
				"}";
		String format_next = String.format(next_step, orderRelationName,stepcode);
		Response response_next = dgraphClient.newReadOnlyTransaction().query(format_next);
		String json_next = Transform.jsonTransform(response_next,"next_step");
		DgraphRelations dgraphRelations_next = gson.fromJson(json_next, DgraphRelations.class);
		if(null != dgraphRelations_next) {
			List<Relation> next_relations = dgraphRelations_next.getRelations();
			map.put("nextRelation", next_relations);
			for(Relation rel:next_relations) {
				String from = stepcode;
				String to = rel.getTo();
				//到态势图中查询占压,并加1
				String type = "add";
				upOccupy(parent,from,to,type);
			}
		}
		return map;
	}
	 
	/**
	 * 更新态势图占压
	 * <p>Title: upOccupy</p>  
	 * <p>Description: </p>  
	 * @param parent
	 * @param from
	 * @param to
	 * @param type
	 */
	private void upOccupy(String parent,String from,String to,String type) {
		Transaction txn = dgraphClient.newTransaction();
		String rel_parent = RELATION_NAME+parent;
		//到态势图中查询占压,并减1
		String parent_rel = "{\n" + 
				"  parent_rel(func:eq(D_relations_name,%s)){\n" + 
				"    uid\n"+
				"    relations @filter(eq(from,%s) and eq(to,%s)){\n" + 
				"      uid\n" + 
				"      from\n" + 
				"      to\n" + 
				"      occupy\n"+
				"      occupy_valid\n"+
				"    }\n" + 
				"  }\n" + 
				"}";
		String format = String.format(parent_rel, rel_parent,from,to);
		Response response = dgraphClient.newReadOnlyTransaction().query(format);
		String json = Transform.jsonTransform(response,"parent_rel");
		DgraphRelations dgraphRelations = gson.fromJson(json, DgraphRelations.class);
		if(dgraphRelations != null) {
			String root_uid = dgraphRelations.getUid();
			List<Relation> tem = dgraphRelations.getRelations();
			for(Relation tmp:tem) {
				String uid = tmp.getUid();
				int occupy = Integer.valueOf(tmp.getOccupy());
				if("reduce".equals(type)) {
					occupy = occupy-1;
				}else {
					occupy = occupy+1;
				}
				String update = "<%s> <relations> <%s> .\r\n" + 
						"<%s> <occupy> \"%s\" .\r\n" ;
				String occ = String.format(update,root_uid, uid,uid,String.valueOf(occupy));
				 Mutation mu =Mutation.newBuilder().setSetNquads(ByteString.copyFromUtf8(occ)).build();
				 txn.mutate(mu);
			}
		}
		txn.commit();
	}
	
	/**
	 * 更新工时
	 * <p>Title: updateWorkHour</p>  
	 * <p>Description: </p>  
	 * @param map
	 * @throws ParseException 
	 */
	public void updateWorkHour(String odid,String stepcode,String empcode,String loaddate) throws ParseException {
		/**
		 * 当前工序+刷卡人 前后两次刷卡时间差
		 * 1.到hbase stepemp 中当前工序+刷卡人 ,能获取到数据，则开始计算工时
		 * 2.将计算的工时更新到当前刷卡记录上
		 * 3.保存数据到stepemp表中
		 * 4.取不到数据，则直接保存数据到stepemp表中
		 * 
		 */
		String stepemp = stepcode +"_"+empcode;
		String pre_date = stepEmpDao.getLoadDate(stepemp);
		//有上次刷卡时间
		if(!StringUtils.isEmpty(pre_date)) {
			/**
			 * 开始计算工时
			 * 1.将字符串的时间转换为date，然后转成毫秒
			 * 2.计算两个毫秒差
			 * 3.转成分钟
			 */
			Date currentDate = df.parse(loaddate);
			long currentMs = currentDate.getTime();
			Date preDate = df.parse(pre_date);
			long preMs = preDate.getTime();
			//秒数
			long ss = (currentMs - preMs) / 1000;
			//分钟
			int mm = (int) ss/60;
			//更新计算出的工时到刷卡表中
			String rowkey = odid+"_"+stepcode;
			brushCardDao.updateWorkHour(rowkey,String.valueOf(mm));
		}
		StepEmpRecord stepEmpRecord = new StepEmpRecord();
		stepEmpRecord.setStepcode_empcode(stepemp);
		stepEmpRecord.setLoadDate(loaddate);
		stepEmpDao.putRecord(stepEmpRecord);
		
	}
	/**
	 * 保存在途时间
	 * <p>Title: saveTransitTime</p>  
	 * <p>Description: </p>  
	 * @param odid
	 * @param stepcode
	 * @param map
	 * @throws ParseException 
	 */
	public void saveTransitTime(String odid,String stepcode,String loaddate,Map<String,Object> map) throws ParseException {
		/**
		 * 1.到hbase brushcard表中根据odid+上道工序 查询数据
		 * 2.获取上道工序的刷卡时间和工时
		 * 3.将当前工序的刷卡时间和上道工序的刷卡时间做差
		 * 4.将差值减去上道工序的工时得出在途时间
		 * 5.保存在途时间到transit表中
		 * 6.更新图数据库中relation 中的在在图时间
		 */
		Transaction txn = dgraphClient.newTransaction();
		List<Relation> preList = (List<Relation>) map.get("preRelation");
		String root_uid = (String) map.get("root_uid");
		for(Relation rel:preList) {
			String from = rel.getFrom();
			String uid = rel.getUid();
			String rowkey = odid +"_"+from;
			String result = brushCardDao.getLoadDate(rowkey);
			if(!StringUtils.isEmpty(result)) {
				String[] arr = result.split("_");
				String preStr = arr[0];
				String workHour = arr[1];
				Date preDate = df.parse(preStr);
				long preMs = preDate.getTime();
				Date currentDate = df.parse(loaddate);
				long currentMs = currentDate.getTime();
				long ss = (currentMs-preMs) /1000;
				int ms = (int) (ss/60);
				//减去上道工序的工时
				int transit = ms - Integer.valueOf(workHour);
				//保存到hbase
				TransitRecord transitRecord = new TransitRecord();
				transitRecord.setOdid_stepcode(odid+"_"+stepcode);
				transitRecord.setPrestep(from);
				transitRecord.setStepcode(stepcode);
				transitRecord.setTransit(String.valueOf(transit));
				transitDao.putRecord(transitRecord);
				//更新到图数据库上
				String update = "<%s> <relations> <%s> .\r\n" + 
						"<%s> <transit> \"%s\" .\r\n" ;
				String transitFormat = String.format(update,root_uid, uid,uid,String.valueOf(transit));
				 Mutation mu =Mutation.newBuilder().setSetNquads(ByteString.copyFromUtf8(transitFormat)).build();
				 txn.mutate(mu);
			}
		}
		txn.commit();
	}
}
